package cn.sylinx.hbatis.ext.starter.pool;

import java.util.Map;
import java.util.Optional;

import javax.sql.DataSource;

import cn.sylinx.hbatis.db.dialect.DbType;
import cn.sylinx.hbatis.ds.DataSourceWrapper;
import cn.sylinx.hbatis.exception.HbatisException;
import cn.sylinx.hbatis.kit.StrKit;
import cn.sylinx.hbatis.log.GLog;

public class DataSourceWrapperFactory {

	public static DataSourceWrapper buildDataSource(Map<String, Object> dsMap, Map<String, Object> extConfig) {
		
		String dbType = Optional.ofNullable(dsMap.get("dbtype")).orElse(DbType.MYSQL.getValue()).toString();
		String pooltype = Optional.ofNullable(dsMap.get("pooltype")).orElse("").toString();

		DataSource dataSource = new DefaultDataSourceSelector(dsMap, extConfig).select(selectPoolType(pooltype));
		if (dataSource == null) {
			throw new HbatisException("缺少数据库连接池，请配置Druid或TomcatJdbc或BoneCP或C3P0或dbcp");
		}
		GLog.debug("dataSource:{} inited, config:{}", dataSource.getClass().getName(), dataSource);
		return DataSourceWrapper.create(dataSource, DbType.getDbType(dbType));
	}

	private static PoolType selectPoolType(String pooltype) {

		PoolType manuSelectPoolType = null;
		if (StrKit.isNotBlank(pooltype)) {
			manuSelectPoolType = PoolType.getPoolType(pooltype);
		}

		if (manuSelectPoolType != null) {
			if (isClassExist(manuSelectPoolType.getClassName())) {
				return manuSelectPoolType;
			}
		}

		if (isDruidExist()) {// 检查cruid连接池是否存在
			return PoolType.Druid;
		} else if (isTomcatJdbcPoolExist()) {
			return PoolType.TomcatJdbc;
		} else if (isBoneCPExist()) {
			return PoolType.BoneCP;
		} else if (isC3P0Exist()) {
			return PoolType.C3P0;
		} else if (isDbcp2Exist()) {
			return PoolType.Dbcp2;
		} else if (isDbcpExist()) {
			return PoolType.Dbcp;
		}
		return null;
	}

	private static boolean isDruidExist() {
		return isClassExist(PoolType.Druid.getClassName());
	}

	private static boolean isTomcatJdbcPoolExist() {
		return isClassExist(PoolType.TomcatJdbc.getClassName());
	}

	private static boolean isDbcp2Exist() {
		return isClassExist(PoolType.Dbcp2.getClassName());
	}

	private static boolean isDbcpExist() {
		return isClassExist(PoolType.Dbcp.getClassName());
	}

	private static boolean isC3P0Exist() {
		return isClassExist(PoolType.C3P0.getClassName());
	}

	private static boolean isBoneCPExist() {
		return isClassExist(PoolType.BoneCP.getClassName());
	}

	private static boolean isClassExist(String className) {
		try {
			Class.forName(className);
		} catch (ClassNotFoundException e) {
			GLog.error("class:{} not foud ", className);
			return false;
		}
		return true;
	}

}
